import _ from 'underscore'
function mergeRule(node, rule) {
  node.rule.push(rule)
  return node
}
export function createValidator(fn) {
  return (rule, value, cb) => {
    fn(value, cb, rule)
  }
}
function requiredRule(node, message) {
  message = message || `${node.label ? node.label : '该项'}为必填项`
  return mergeRule(node, { required: true, message, trigger: ['blur'] })
}
function typeRule(node, message) {
  message = message || `请输入正确的类型: ${node.type}`
  return mergeRule(node, { type: node.type, message, trigger: ['blur'] })
}
function lenRule(node, len, message) {
  message = message || `${node.label}的长度必须为${len}位`
  return mergeRule(node, { len, message, trigger: ['blur'] })
}
function maxLenRule(node, max, message) {
  message = message || `${node.label}的长度最多为${max}位`
  return mergeRule(node, { max, message, trigger: ['blur'] })
}
function minLenRule(node, min, message) {
  message = message || `${node.label}的长度至少为${min}位`
  return mergeRule(node, { min, message, trigger: ['blur'] })
}
function arrayRule(node) {
  for (let rule of node.rule) {
    if (rule.required) {
      rule.type = 'array'
      return node
    }
  }
  return mergeRule(node, { type: 'array', message: '请输入一个数组' })
}
function minRule(node, min) {
  let validator = createValidator((val, cb) => {
    (
      val && !/^(-?\d+)(\.\d+)?$/.test(val)
    ) || (
        parseFloat(val, 10) < min
      ) ? cb(new Error(`必须输入一个不小于${min}的数字`)) : cb()
  })
  return mergeRule(node, { validator })
}
function timeRule(node) {
  let validator = createValidator((val, cb) => {
    let startTime = val[0], endTime = val[1];

    if (!startTime || !endTime) {
      cb(new Error('开始时间或者结束时间不能为空'))
    } else if ((new Date(endTime).getTime() - new Date(startTime).getTime()) < 0) {

      cb(new Error('结束时间必须大于开始时间'));
    } else {
      cb()
    }
  })
  return mergeRule(node, { validator })
}
function maxRule(node, max) {
  let validator = createValidator((val, cb) => {
    (
      val && !/^(-?\d+)(\.\d+)?$/.test(val)
    ) || (
        parseFloat(val, 10) > max
      ) ? cb(new Error(`必须输入一个不大于${max}的数字`)) : cb()
  })
  return mergeRule(node, { validator })
}
function int(node) {
  let validator = createValidator((val, cb) => {
    // 即使val不存在的时候也可以执行
    // if (val.toString().trim() === '') {----之前的做法
    if (!val || val.toString().trim() === '') {
      cb()
      return
    }
    parseInt(val).toString() === val.toString() ? cb() : cb(new Error('必须输入一个整数'))
  })
  return mergeRule(node, { validator })
}

function number(node) {
  let validator = createValidator((val, cb) => {
    val = String(val).trim();
    Number(val) ? cb() : cb(new Error('必须输入一个数字'))
  })
  return mergeRule(node, { required: true, validator })
}

function phone(node) {
  let validator = createValidator((val, cb) => {
    /^1[345789]\d{9}$/.test(val) ? cb() : cb(new Error('请输入正确的手机号码'))
  })
  return mergeRule(node, { required: true, validator })
}
function tel(node) {
  let validator = createValidator((val, cb) => {
    (
      /^1[34578]\d{9}$/.test(val) || /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/.test(val)
    ) ? cb() : cb(new Error('请输入正确电话号码,如(xxx-xxxxxxxx)'))
  })
  return mergeRule(node, { validator })
}

function passwd(node, mod, modFild, checkFild) {
  let validator = createValidator((val, cb) => {
    let _value = mod[modFild][checkFild].value
    if (!val) {
      cb(new Error('密码不能为空'))
    } else if (val !== _value && _value) {
      cb(new Error('两次输入密码不一致，请重新输入'))
    } else {
      cb();
    }
    //

  })
  return mergeRule(node, { required: true, validator})
}

function charAndNumRule(node) {
  let validator = createValidator((val, cb) => {
    (
      /^.[a-zA-z0-9]+$/.test(val)
    ) ? cb() : cb(new Error('这里不能输入除字母和数字外的字符'))
  })
  return mergeRule(node, { validator })
}

function checkUrl(node) {
  let type = node.type;
  let validator = createValidator((val, cb) => {
    /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(val) ? cb() : cb(new Error('请输入正确的url'))
  })
  return mergeRule(node, { required: true, validator })
}

function checkUpLoad(node) {
  // let type = node.type;
  let validator = createValidator((val, cb) => {

    let temp = !val ? {} : JSON.parse(val);
    Object.values(temp).length < node.limit ? cb(new Error(`最少上传${node.limit}张图片`)) : cb()
  })
  return mergeRule(node, { required: true, validator })
}


function label(node, label) {
  node.label = label
  return node
}
function rule(node, rule) {
  node.rule = rule || []
  return node
}
function type(node, type) {
  node.type = type || 'text'
  return node
}
function icon(node, icon) {
  node.icon = icon
  return node
}
function text(node, text) {
  node.text = text
  return node
}
function prefix(node, prefix) {
  node.prefix = prefix
  return node
}
function step(node, step) {
  node.step = step
  return node
}
function nativeType(node, nativeType) {
  node.nativeType = nativeType || 'text'
  return node
}
function placeholder(node, placeholder) {
  node.placeholder = placeholder || `请${node.type !== 'select' ? '输入' : '选择'}${node.label}`
  return node
}
function protect(node, bool) {
  node.protect = bool || false
  return node
}
function required(node, bool) {
  node.required = bool || false
  return node
}
function disabled(node, bool) {
  node.disabled = bool || false
  return node
}
function clearable(node, bool) {
  node.clearable = bool || false
  return node
}
function val(node, val) {
  node.value = val || ''
  return node
}
function options(node, options) {
  node.options = options || []
  return node
}
function append(node, append) {
  node.append = append
  return node
}
function prepend(node, prepend) {
  node.prepend = prepend
  return node
}
function disclosable(node, disclosable) {
  node.disclosable = disclosable
  return node
}
function filterable(node, filterable) {
  node.filterable = filterable
  return node
}
function multiple(node, multiple) {
  node.multiple = multiple
  multiple && this.arrayRule(node)
  return node
}
function helper(node, arr) {
  node.helper = arr
  return node
}
function checkDefault(node) {
  return _.placeholder(node, node.placeholder)
}
function rows(node, rows) {
  node.rows = rows
  return node
}
function setValue(node, options) {
  // node[key] = val
  for (let key in options) {
    node[key] = options[key]
  }
  return node;
}

let proto = {
  // 表单子项配置信息
  rule,
  mergeRule,
  text,
  label,
  append,
  prepend,
  prefix,
  protect,
  helper,
  int,
  phone,
  tel,
  minRule,
  maxRule,
  lenRule,
  typeRule,
  arrayRule,
  maxLenRule,
  minLenRule,
  requiredRule,
  charAndNumRule,
  timeRule,
  disclosable,
  checkUrl,
  checkUpLoad,
  number,
  passwd,
  // 表单输入框配置信息
  val,
  type,
  icon,
  step,
  options,
  nativeType,
  placeholder,
  checkDefault,
  required,
  disabled,
  clearable,
  filterable,
  multiple,
  rows,
  setValue
}

let mixin = _.reduce(Object.keys(proto), function (mixin, key) {
  mixin[key] = proto[key]
  return mixin
}, {})

mixin.default = function defaultVal(node, val) {
  node.default = val;
  node.value = val;
  return node
}
_.mixin(mixin)
// 默认设置required,disabled,protect等属性，以使这些属性具备响应式
let base = function () {
  return _.chain({}).val().required().disabled().protect().rule()
}
export function input() {
  return base().type('text')
}
export function select() {
  return base().type('select').options([]).filterable(false).disabled(false).multiple(false).clearable(false).disclosable(false)
}
export function opt() {
  return _.chain({}).val().rule()
}
export function requiredInput() {
  return input().required(true).requiredRule()
}
export function requiredSelect() {
  return select().required(true).requiredRule()
}
export function clone(C) {
  return new C()
}

